﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Data.Linq;
using System.Text;
using System.Windows.Forms;
using Newtonsoft.Json.Linq;
using BLL = KC.Business.Stockmaster.JsonLookups;

namespace KC.Presentation.Stockmaster
{
	public partial class NewMonitor : Form
	{
		private string username, password;
		private int numIterations = 0;
		private DataTable dtNew = new DataTable();
        private List<string> NotWorthTwitters = new List<string>();
        public Dictionary<string, int> AutoBuys = new Dictionary<string, int>(), CantBuys = new Dictionary<string, int>();


		public NewMonitor(string Username, string Password)
		{
			InitializeComponent();
			username = Username;
			password = Password;
		}

		private void btnClose_Click(object sender, EventArgs e)
		{
			Close();
		}

		private void NewMonitor_Load(object sender, EventArgs e)
		{
			tNew.Start();
		}

		private void tNew_Tick(object sender, EventArgs e)
		{
			if ((username.Trim().ToUpper() == "TSILB" || username.Trim().ToUpper() == "IX") || numIterations == 0)
				UpdateGrid();
			List<string> TickersToBuy = null;

			// AutoBuy Smart Mode: Buy tickers likely to jump
			if (rbSmartMode.Checked) {
				AddOutput("AutoBuy Smart Mode: Looking up new, unowned tickers with >= 100 followers and followees...");
				TickersToBuy = GetSmartTickers();
                if (TickersToBuy == null)
                    return;
				if (username.ToUpper().Trim() != "TSILB" && username.ToUpper().Trim() != "IX") System.Threading.Thread.Sleep(5000); // Mwuhahahahaha!
				AddOutput("New stocks to buy: " + string.Join(", ", TickersToBuy.ToArray<string>())); }

			// AutoBuy Semi Smart Mode: Buy all new tickers that have a portrait and are below $10.20
			else if (rbSemiSmart.Checked) {
				AddOutput("AutoBuy SemiSmart Mode: Looking up new tickers with portraits and prices below $10.20...");
				if (username.ToUpper().Trim() != "TSILB" && username.ToUpper().Trim() != "IX") System.Threading.Thread.Sleep(5000); // Mwuhahahahaha!
				TickersToBuy = GetSemiSmartTickers(); }

			// AutoBuy Dumb Mode: Buy all new tickers the user doesn't currently own
			else if (rbAutoBuy.Checked) {
				AddOutput("AutoBuy Dumb Mode: Looking up all new but unowned stocks...");
				TickersToBuy = GetDumbTickers(); }

			// Filter out the buy cache
			if (TickersToBuy == null)
				return; // probably an API limit reached
			for (int i = TickersToBuy.Count - 1; i >= 0; i--)
				if (AutoBuys.ContainsKey(TickersToBuy[i]))
					TickersToBuy.RemoveAt(i);

			// Buy the tickers we decided on above
			if (TickersToBuy != null && TickersToBuy.Count > 0) {
				AddOutput("Stocks to buy: " + string.Join(", ", TickersToBuy.Where(t => !AutoBuys.ContainsKey(t))));
				foreach (string ticker in TickersToBuy) {
					// Skip tickers we've bought before
					int unused;
					try {
						unused = AutoBuys[ticker];
						if (unused > 0) {
							AddOutput(ticker + " already bought " + unused.ToString() + " shares; skipping");
							continue; } }
					catch (KeyNotFoundException) { }
                    if (CantBuys.ContainsKey(ticker)) {
                        AddOutput("Previously failed to buy " + ticker + "; skipping");
                        continue; }

					// get stock price from dataset
					double price = -1;
					foreach (DataRow dr in dtNew.Rows)
						if (dr["ticker"].ToString().Trim().ToLower() == ticker.Trim().ToLower())
							price = double.Parse(dr["last_trade"].ToString());
					if (price == -1) continue;

					// Buy, Buy, Buy!
					string strResult = "";
					if (username.ToUpper().Trim() != "TSILB" && username.ToUpper().Trim() != "IX") System.Threading.Thread.Sleep(1000); // Mwuhahahahaha!
					try {
						strResult = KC.Business.Stockmaster.JsonPosts.Buy(username, password, ticker, slider.Value, price);
                        if (strResult.ToUpper().Contains("SUCCESS"))
                            AutoBuys.Add(ticker, slider.Value);
						else if (strResult.ToUpper().Contains("\"error\":\"107")) {
							AddOutput("Can't buy more " + ticker + "; too many shares already owned.");
                            
							CantBuys.Add(ticker, -1); 
                        }
						else if (strResult.ToUpper().Contains("\"error\":")) {
							AddOutput("Can't buy more " + ticker + "; error code " + ((Dictionary<string, dynamic>)BLL.DeserializeJson(strResult))["meta"]["error"].ToString());
							CantBuys.Add(ticker, -1); 
                        }
						else AddOutput("ERROR buying " + ticker);
					}
					catch (Exception ex) { AddOutput(ticker + ": " + ex.Message); continue; }

					if (strResult.ToUpper().Contains("SUCCESS")) AddOutput("Bought " + slider.Value.ToString() + " shares of " + ticker);
					else AddOutput("Error buying " + ticker + ": " + strResult); }
				AddOutput("Done buying stocks");
			}
			if (username.Trim().ToUpper() != "TSILB" && username.Trim().ToUpper() != "IX") UpdateGrid();
		}

		private void UpdateGrid()
		{
			numIterations++;
            string strJson;
            try { strJson = BLL.NewStocks(username, password); }
            catch (System.Net.WebException ex)
            {
                AddOutput("Error looking up new stocks: " + ex.Status.ToString() + " / " + ex.ToString());
                return;
            }
            catch (Exception ex)
            {
                AddOutput("Error looking up new stocks: " + ex.ToString());
                return;
            }
            Dictionary<string, dynamic> result = null;
			if (strJson.Contains("Exceeded")) {
				label1.Text = "API Status: API limit exceeded. Empire Avenue resets this flag once per hour.";
				AddOutput(label1.Text);
				return; }
			else label1.Text = "API Status: Everything is OK";
            try { result = BLL.DeserializeJson(strJson); }
            catch (Exception ex) {
                AddOutput("Error reading API result: " + ex.Message);
                return; }

			// build columns
			JToken meta, data;
			try {
				meta = (JToken)result["meta"];
				data = (JToken)result["data"];
				label1.Text = "API Status: Everything is OK"; }
			catch (KeyNotFoundException) {
				label1.Text = "API Status: API limit exceeded. Empire Avenue resets this flag once per hour.";
				return; }

			if (dtNew.Columns.Count == 0) {
				foreach (JProperty prop in data[0])
					if (!dtNew.Columns.Contains(prop.Name))// && new string[] { "full_name", "country", "location", "ticker", "last_trade", "created" }.Contains(prop.Name.ToLower()))
						dtNew.Columns.Add(prop.Name);
				dtNew.Columns.Add("iteration", typeof(int)); }

			// Remove preexisting record from table (so we keep updating the prices)
			foreach (JObject obj in data)
				for (int i = 0; i < dtNew.Rows.Count; i++)
					if ((string)(dtNew.Rows[i]["ticker"]) == ((JValue)((JToken)(obj))["ticker"]).Value.ToString())
						dtNew.Rows.RemoveAt(i);

			// build rows
			for (int i = 0; i < data.Count(); i++) {
				DataRow dr = dtNew.NewRow();
				foreach (JProperty prop in data[i])
					if (dtNew.Columns.Contains(prop.Name))
					dr[prop.Name] = prop.Value.ToString();
				dr["iteration"] = numIterations.ToString();

				if (dr["sm_portrait"].ToString() == "http://www.empireavenue.com/public/portraits/placeholder_sm.jpg")
					dr["sm_portrait"] = "";

				// Add row if unique ticker
				bool isDupe = false;
				foreach (DataRow row2 in dtNew.Rows)
					if (row2["ticker"].ToString() == dr["ticker"].ToString())
						isDupe = true;
				if (!isDupe)
					dtNew.Rows.Add(dr); }

			// Sort and bind
			dtNew.DefaultView.Sort = "Created DESC, iteration DESC";
			dgvNew.DataSource = dtNew;
			if (dgvNew.Rows.Count > 0)
				dgvNew.FirstDisplayedCell = dgvNew.Rows[0].Cells[0];
			dgvNew.ClearSelection();

			// Colorize that bitch 
			foreach (DataGridViewRow dgvr in dgvNew.Rows)
			{
				// by iteration newness
				if ((int)dgvr.Cells["iteration"].Value == numIterations)
					dgvr.DefaultCellStyle.BackColor = Color.White;
				else dgvr.DefaultCellStyle.BackColor = Color.FromArgb(225, 225, 225);

				// by stock price awesomeness
				if (double.Parse((string)dgvr.Cells["last_trade"].Value) < 10)
					dgvr.Cells["last_trade"].Style.BackColor = Color.FromArgb(255,150,150);
				else if (double.Parse((string)dgvr.Cells["last_trade"].Value) > 30)
					dgvr.Cells["last_trade"].Style.BackColor = Color.LightBlue;
				else if (double.Parse((string)dgvr.Cells["last_trade"].Value) > 22)
					dgvr.Cells["last_trade"].Style.BackColor = Color.LightGreen;
				else if (double.Parse((string)dgvr.Cells["last_trade"].Value) > 18)
					dgvr.Cells["last_trade"].Style.BackColor = Color.Yellow;
			}

			

		}

		// TODO: Predict tickers
		private List<string> GetDumbTickers()
		{
			// Get a list of all tickers in the newest iteration
			List<string> tickersToBuy = new List<string>();
			foreach (DataRow dr in dtNew.Rows)
				if (dr["iteration"].ToString() == numIterations.ToString())
					tickersToBuy.Add(dr["ticker"].ToString());
			return BLL.FilterStocksByOwned(username, password, tickersToBuy);
		}
		private List<string> GetSemiSmartTickers()
		{
			// Get a list of all tickers in the newest iteration
            List<string> tickersToBuy = new List<string>();
			foreach (DataRow dr in dtNew.Rows) {
			    DateTime created = DateTime.Parse(dr["created"].ToString());
			    if (dr["iteration"].ToString() == numIterations.ToString()		&& !string.IsNullOrEmpty(dr["sm_portrait"].ToString()) 
					&& double.Parse(dr["last_trade"].ToString()) < 10.5			&& created > DateTime.UtcNow.AddMinutes(-10))
			        tickersToBuy.Add(dr["ticker"].ToString());}
			return BLL.FilterStocksByOwned(username, password, tickersToBuy);
		}
		private List<string> GetSmartTickers()
		{
			//KC.Business.Stockmaster.Twitter.JsonLookups.GetTwitterRequestToken();
			// Get a list of all tickers in the newest iteration
            List<string> tickersToBuy = new List<string>();
			foreach (DataRow dr in dtNew.Rows) {
			    DateTime created = DateTime.Parse(dr["created"].ToString());
			    if (dr["iteration"].ToString() == numIterations.ToString() && created > DateTime.UtcNow.AddMinutes(-30) && !NotWorthTwitters.Contains(dr["ticker"].ToString())) {
                    try { 
                    if (KC.Business.Stockmaster.Web.IsWorthBuying(dr["ticker"].ToString(), username, password)) {
                        AddOutput(dr["ticker"].ToString() + ": Twitter is worthy of buying! Added to list.");
                        tickersToBuy.Add(dr["ticker"].ToString()); }
                    else {
                        NotWorthTwitters.Add(dr["ticker"].ToString().Trim());
                        AddOutput(dr["ticker"].ToString() + ": Twitter is unworthy of buying; skipping."); }  }
                    catch {
                        AddOutput("Error detecting Twitter worthiness; skipping.");
                        continue; }

                } }

            // Filter out owned tickers
            AddOutput("Tickers worth buying: " + tickersToBuy.Count.ToString());
            tickersToBuy = BLL.FilterStocksByOwned(username, password, tickersToBuy);
            AddOutput("Tickers worth buying and not owned: " + tickersToBuy.Count.ToString());
			return tickersToBuy;
		}

		private void rbOff_CheckedChanged(object sender, EventArgs e)
		{
			if (rbOff.Checked) { rbAutoBuy.Checked = false; rbSmartMode.Checked = false; rbSemiSmart.Checked = false; }
            foreach (DataRow dr in dtNew.Rows)
                if (!AutoBuys.ContainsKey(dr["ticker"].ToString()) && !CantBuys.ContainsKey(dr["ticker"].ToString()))
                    CantBuys.Add(dr["ticker"].ToString(), -1);
		}
		private void rbAutoBuy_CheckedChanged(object sender, EventArgs e)
		{
			if (rbAutoBuy.Checked) { rbOff.Checked = false; rbSmartMode.Checked = false; rbSemiSmart.Checked = false; }
            foreach (DataRow dr in dtNew.Rows)
                if (!AutoBuys.ContainsKey(dr["ticker"].ToString()) && !CantBuys.ContainsKey(dr["ticker"].ToString()))
                    CantBuys.Add(dr["ticker"].ToString(), -1);
        }
		private void rbSemiSmart_CheckedChanged(object sender, EventArgs e)
		{
			if (rbAutoBuy.Checked) { rbOff.Checked = false; rbSmartMode.Checked = false; rbAutoBuy.Checked = false; }
            foreach (DataRow dr in dtNew.Rows)
                if (!AutoBuys.ContainsKey(dr["ticker"].ToString()) && !CantBuys.ContainsKey(dr["ticker"].ToString()))
                    CantBuys.Add(dr["ticker"].ToString(), -1);
        }
		private void rbSmartMode_CheckedChanged(object sender, EventArgs e)
		{
			if (rbSmartMode.Checked) { rbOff.Checked = false; rbAutoBuy.Checked = false; rbSemiSmart.Checked = false; }
            foreach (DataRow dr in dtNew.Rows)
                if (!AutoBuys.ContainsKey(dr["ticker"].ToString()) && !CantBuys.ContainsKey(dr["ticker"].ToString()))
                    CantBuys.Add(dr["ticker"].ToString(), -1);
        }

		private void NewMonitor_FormClosing(object sender, FormClosingEventArgs e)
		{
			Enabled = false;
			tNew.Enabled = false;
			tNew.Stop();
		}
		private void AddOutput(string output)
		{
			txtOutput.Text += DateTime.Now.ToString("HH:mm:ss") + ": " + output + "\r\n";
			txtOutput.SelectionStart = txtOutput.Text.Length - 1;
			txtOutput.ScrollToCaret();
		}
		private void dgvNew_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
		{
			string ticker;
			try { ticker = dgvNew.Rows[e.RowIndex].Cells["ticker"].Value.ToString(); }
			catch { return; }
			System.Diagnostics.Process.Start("http://www.empireavenue.com/" + ticker);
		}
		private void slider_Scroll(object sender, EventArgs e)
		{
			lblShares.Text = slider.Value.ToString();
		}
	}
}
